package com.avic.gateway.common.annotation.impl;

import com.avic.gateway.common.annotation.ImportFilters;
import com.netflix.zuul.FilterFactory;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.filters.FilterRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportAware;
import org.springframework.core.annotation.Order;
import org.springframework.core.type.AnnotationMetadata;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * <p>zuul过滤器注册器</p>
 */
@Configuration
@Order(100)
public class ZuulFilterRegister implements ImportAware, CommandLineRunner {
    /**
     * 日志记录器
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(ZuulFilterRegister.class);

    /**
     * 引入过滤器注解类
     */
    private static final Class IMPORT_FILTER_ANNOTATION_CLASS = ImportFilters.class;

    /**
     * 过滤器工厂字段名
     */
    private static final String FILTER_FACTORY_FIELD_NAME = "filterFactory";

    /**
     * 过滤器类型列表字段名
     */
    private static final String FILTER_CLASSES_FIELD_NAME = "filters";

    /**
     * 注解元数据
     */
    private static AnnotationMetadata importMetadata;

    /**
     * @see CommandLineRunner#run(String...)
     */
    public void run(String... args) throws Exception {
        try {
            List<ZuulFilter> zuulFilters = resolveZuulFilters(importMetadata);
            addLocalFilters(zuulFilters);
        } catch (Exception e) {
            LOGGER.error("加载过滤器时发生异常.", e);
        }
    }

    /**
     * 从注解元数据中解析出过滤器数据
     *
     * @param importMetadata 程序入口的注解元数据
     * @return 过滤器数据
     * @throws Exception
     */
    @SuppressWarnings("unchecked")
    private static List<ZuulFilter> resolveZuulFilters(AnnotationMetadata importMetadata) throws Exception {
        String importFilterAnnotationClassName = IMPORT_FILTER_ANNOTATION_CLASS.getName();
        if (!importMetadata.hasAnnotation(importFilterAnnotationClassName)) {
            return null;
        }

        Class<? extends FilterFactory> filterFactoryClass = (Class<? extends FilterFactory>) importMetadata.getAnnotationAttributes(importFilterAnnotationClassName).get(FILTER_FACTORY_FIELD_NAME);
        Class<? extends ZuulFilter>[] zuulFilterClasses = (Class<? extends ZuulFilter>[]) importMetadata.getAnnotationAttributes(importFilterAnnotationClassName).get(FILTER_CLASSES_FIELD_NAME);

        List<Class<? extends ZuulFilter>> zuulFilterClassList = Arrays.asList(zuulFilterClasses);

        if (null == zuulFilterClassList || zuulFilterClassList.size() <= 0) {
            return null;
        }

        FilterFactory filterFactory = filterFactoryClass.newInstance();
        List<ZuulFilter> zuulFilters = new ArrayList<ZuulFilter>(zuulFilterClassList.size());
        for (Class<? extends ZuulFilter> filterClazz : zuulFilterClassList) {
            ZuulFilter zuulFilter = filterFactory.newInstance(filterClazz);
            zuulFilters.add(zuulFilter);
        }
        return zuulFilters;
    }

    /**
     * 添加本地过滤器
     *
     * @param zuulFilters 过滤器列表
     */
    private static void addLocalFilters(List<ZuulFilter> zuulFilters) {
        if (null == zuulFilters || zuulFilters.size() <= 0) {
            return;
        }

        for (ZuulFilter zuulFilter : zuulFilters) {
            String zuulFilterName = zuulFilter.getClass().getName();
            FilterRegistry.instance().put(zuulFilterName, zuulFilter);
            LOGGER.info("向本地过滤器注册器中添加过滤器 {} 成功", zuulFilterName);
        }
    }

    /**
     * @see ImportAware#setImportMetadata(AnnotationMetadata)
     */
    public void setImportMetadata(AnnotationMetadata importMetadata) {
        ZuulFilterRegister.importMetadata = importMetadata;
    }
}
